﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using YasharEl.Infrastructure.ApplicationModel.Modularity.Bootstrap;
using YasharEl.Infrastructure.ApplicationModel.Bootstrap.Configuration;
using YasharEl.Infrastructure.Caching.Configuration;
using YasharEl.Infrastructure.Caching.Orm;
using YasharEl.Infrastructure.Caching;

namespace YasharEl.Infrastructure.ApplicationModel.Bootstrap.Extensions
{
    public class CachingBootstrapperExtension : ModuleComponentBootstrappingExtension, IConsumeConfigurationSection
    {
        #region Properties

        public CachingConfig CachingConfigSection { get; private set; }

        #endregion

        #region BaseComplexBootstrappingExtension Abstract Overrides

        public override string Describe()
        {
            return "Extension which configure and start caching cross cutting aspects.";
        }

        #endregion

        #region IConsumeConfigurationSection Implementations

        public void Apply(ConfigurationSection section)
        {
            CachingConfigSection = section as CachingConfig;
        }

        #endregion

        #region BaseComplexBootstrappingExtension Virtual Overrides

        public override void Configure()
        {
            try
            {
                Logger.Debug("Configuring caching...");

                if (CachingConfigSection == null ||
                    CachingConfigSection.CacheManagers == null ||
                    CachingConfigSection.CacheManagers.Count == 0)
                    throw new InvalidSystemConfigurationException("Caching cross cutting feature requested but not correctly configured.Check you config files.");

                foreach (CacheManagerConfig cacheManagerConfig in CachingConfigSection.CacheManagers)
                {
                    Logger.Debug("Configuring cache manager with name : {0}", cacheManagerConfig.Name);

                    ICacheManager cacheManager = cacheManagerConfig.CreateCacheManager(
                        Container.DependencyRegistrar
                    );

                    Logger.Debug("Cache manager with name '{0}' successfully configured and registered to container.", cacheManagerConfig.Name);
                }

                List<IOrmCacheManager> ormCacheManagers = new List<IOrmCacheManager>(
                    Container.DependencyResolver.ResolveAllInstances<IOrmCacheManager>()
                );

                if (ormCacheManagers != null && ormCacheManagers.Count > 0)
                {
                    IOrmCacheManager defaultOrmCacheManager = ormCacheManagers.Find((m) => m.Name == CachingConfigSection.OrmCacheManagerName);
                    if (defaultOrmCacheManager == null)
                    {
                        throw new InvalidSystemConfigurationException(
                            string.Format("Orm cache manager with name {0} not exists.", CachingConfigSection.OrmCacheManagerName)
                        );
                    }

                    // Register orm cache manager as default (without name)
                    Container.DependencyRegistrar.Register<IOrmCacheManager>(defaultOrmCacheManager, true);
                }
            }
            catch (Exception ex)
            {
                Logger.Error(ex, "Error configuring caching.");
                throw;
            }
        }

        #endregion

        #region ModuleComponentBootstrappingExtension Overrides

        public override string SectionName
        {
            get { return CachingConfig.CachingConfigDefaultSectionName; }
        }

        #endregion
    }
}
